//
//  XMLParserWorker.m
//  OR_1
//
//  Created by Luboš Kulič on 8/21/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "XMLParserWorkers.h"

#import "ORShortcutsParser.h"
#import "Stack.h"
#import <objc/runtime.h>

@implementation DataElement

+(DataElement *)elementWithName:(NSString *)name_ Data:(NSString *)data_ {
	return [[[self alloc] initWithName:name_ Data:data_] autorelease];
}

-(id)initWithName:(NSString *)name_ Data:(NSString *)data_{
	if (!(self=[super init])) return nil;
	name = [name_ retain];
	data = [data_ retain];
	return self;
}

-(void)dealloc {
	[name autorelease];
	[data autorelease];
	[super dealloc];
}


-(NSString *) description {
	return [NSString stringWithFormat: @"DataElement {%@, %@}", name, data];
}

-(NSString *) name {
	return self->name;
}
-(NSString *) data {	
	return self->data;
}

@end




///////////////////////////////////////////////////



static NSMutableDictionary *elementParsers = 0;

static NSMutableSet *complexItems=0, *arrayItems=0, *simpleItems=0;

static NSString * defaultElementName = @"<<<<DUMMY_ELEMENT_NAME>>>>";



@implementation XMLParserWorker



+(NSString *) parsedElementName {
	return defaultElementName;
}


-(NSString *) description {
	return [NSString stringWithFormat:@"Worker data: %@",[retData description] ]	;
}


/// every class calls the Worker to register itself with names of elements
/// it does so by implementing +load method in which it calls XMLParserWorker::+registerParser
/// with an instance of itself
/// +load method is guaranteed to be called for every class implementing it and +load of super class is
/// called first => thus after the application load, all subclasses will be registered

+(void) load {
	if( self == [XMLParserWorker class] ) {
		// really this class's init		
		elementParsers = [[NSMutableDictionary dictionary] retain];	// deprecated
		
		// TODO - constants for XML elements
		complexItems = [[NSMutableSet alloc] initWithObjects:
						@"D:Vypis_OR"
						,@"D:ZAU" // zakladni udaje
						,@"are:Zaznam"			
						,@"D:C" // clen, napr. predstavenstva
						,@"D:SI" // adresa
						,nil
		];
		
		simpleItems = [[NSMutableSet setWithCapacity:10] retain];
		
		arrayItems = [[NSMutableSet alloc] initWithObjects:
					  @"D:CIN" // cinnosti	
					  ,@"D:SO", @"SOP" // statutarni organy
					  ,nil
					  ];
	}
}


+(void) registerParser:(Class)parser ForElement:(NSString *) elementName {
	NSLog(@"parser: %@, forElement: %@", parser, elementName);
	//[elementParsers setValue:parser forKey:elementName];	
}


-(XMLParserWorker *) getParserForElement:(NSString *)elementName {
	
	if([complexItems containsObject:elementName]) {
		return [[[XMLParserWorkerNamedData alloc] initWithName:elementName] autorelease];
	}
	else if([arrayItems containsObject:elementName] ) {
		return [[[XMLParserWorkerArrayData alloc] initWithName:elementName] autorelease];
	}
	else {
		return 0;
	}
}


-(void)initAuxData {
	if(!elementStack) {
		elementStack = [[Stack stack] retain];
	} else {
		[elementStack removeAllObjects];
	}
	
	if(!dataStack) {
		dataStack = [[Stack stack] retain];
	} else {
		[dataStack removeAllObjects];
	}
	
	[retData autorelease];
	retData = [[NSMutableDictionary dictionary] retain];
}


-(id) init {
	return [self initWithName:@"<<XMLParserWorker_DummyName>>"];
}

-(id) initWithName:(NSString *) name {
	if(self = [super init]) {
		translator = [[ORShortcutsParser getORShortcutsTranslator] retain];
		[self initAuxData];
		elementName = [name retain];
	}
	
	return self;
}



-(void) dealloc {
	
	// TODO - use dealloc instead??
	[translator autorelease];
	[dataStack autorelease];
	[elementStack autorelease];
	[super dealloc];
	
}





/********************************************************************/


-(void) parserWillStartSubelement:(NSString *)elementName withWorker:(XMLParserWorker *)newWorker{
	// Do nothing
}

-(void) parserDidEndRootElementWithData:(NSString *)parsedElementData {
	// Do nothing	
}

-(void) pushParsedDataAndElement:(NSString *)elementName {
	// put element on to the stack -- DO WE REALLY NEED THAT?
	[elementStack push:elementName];
	[dataStack push:[NSMutableString string]]; // the container automatically retains
}



-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
	//NSLog(@"Element: %@",  elementName);
	
	
	//NSLog(@"Push for Element %@ in worker %@", elementName, rootElementName_);
	
	XMLParserWorker * newWorker = [self getParserForElement:elementName];
	
	if(newWorker) {		
		// call a callback for subclasses -> subelement is properly stored
		[self parserWillStartSubelement:elementName withWorker:newWorker];
		
		// let the new worker start its own data storage
		[newWorker pushParsedDataAndElement:elementName];
		
		// pass the control to the new worker
		newWorker->previousWorker = self;
		[parser setDelegate:newWorker];
	} else {
		// the worker should parse the element itself
		// -> create storage for the new element
		
		// add the data to the descriptions array
		[self pushParsedDataAndElement:elementName];		
	}


}


-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
	//NSLog(@"End el: %@",  elementName);
	
	//NSLog(@"Pop for element: %@ in worker: %@", elementName, rootElementName_);
	
	// remove the element name from the stack -- DO WE REALLY NEED THAT?
	[elementStack pop];
	//NSLog(@"Popped el");
	
	// get the current element data
	
	NSMutableString * data = [dataStack pop] ;
	
	//NSLog(@"Popped data");
	
	// check for emty data
	NSString * correctedData = [data stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
	
	if (!correctedData || [correctedData isEqualToString:@""]) {
		correctedData = 0;
	} else {
		// we'll store this
		[correctedData retain]; 
	}
	
	if ([self->rootElementName_ isEqualToString:elementName]) {
		// means we ended parsing root element of this worker 
		// call the callback for business action
		[self parserDidEndRootElementWithData:correctedData];
		[parser setDelegate:previousWorker];
	} else {
		DataElement * element = [DataElement elementWithName:elementName Data:correctedData];
		
		[retData setObject:element forKey:elementName];
		
	}	
}

-(void) parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock {
	NSLog(@"CDATA: %@", CDATABlock);
}


-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
	//NSLog(@"Data: %@", string);	
	
	// apend data to the last item on the data stack
	[[dataStack lastObject] appendString:string];
	//NSLog(@"dataStack: %@", dataStack);
}

-(void)parser:(NSXMLParser *)parser foundIgnorableWhitespace:(NSString *)whitespaceString{
	NSLog(@"Ignorable wsp: %@", whitespaceString);
}








/********************************************************************/
// deprecated






+(BOOL) isSubclassOfClass:(Class)class {
	return NO;
	
}

/// Initializes the whole XMLParserWorker tree - i.e. asks every descendant to register itself for some element name
+(void) initialize_old {
	elementParsers = [NSMutableDictionary dictionary];
	
	int classCount = objc_getClassList(0, 0);
	
	// get current class
	
	Class * classes = malloc(sizeof(Class) * classCount);
	
	classCount = objc_getClassList(classes, classCount);
	
	for (int i = 0; i < classCount; ++i) {
		Class c = classes[i];
		
		// check whether subclass of this class
		
	}
	
	//[self class]; 
	
}




@end
















